﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using System.Drawing.Drawing2D;

using System.Windows.Forms;
using Athena.Objects;
using Athena.Core;

namespace Athena.Tools
{
    public class AnchorTool : INonVisualTool
    {

        enum State { Aliasing, Anchoring };
        
        List<IDrawable> _ItemsToConnect;
        
        private static AnchorTool _oInstance = new AnchorTool();

        public static AnchorTool Instance
        {
            get { return _oInstance; }
        }

        private AnchorTool()
        {
            _ItemsToConnect = new List<IDrawable>();

            // has items to put into context menu
            _bHasContextMenuItems = true;
            _bHasMenuItems = true;

            ToolManager.Instance.RegisterTool("Anchor Tool", "Link items together", this);

        }

        public override ToolManager.Order Order
        {
            get
            {
                return ToolManager.Order.MIDDLE;
            }
        }

        ToolStripButton _Anchor = null, _Alias = null;

        public override void SetupToolStrip(ToolStrip oToolstrip)
        {
            _oStrip = oToolstrip;

            ToolStripButton _oAnchor = new ToolStripButton(Utility.GetResource("anchor"));// anchor
            _oAnchor.ImageScaling = ToolStripItemImageScaling.None;
            _oAnchor.Click += new EventHandler(_oAnchor_Click);
            _oAnchor.ToolTipText = "Anchor selected items to another item";
            oToolstrip.Items.Add(_oAnchor);
            _Anchor = _oAnchor;

            oToolstrip.Items.Add("-");

            ToolStripButton _oAlias = new ToolStripButton(Utility.GetResource("alias"));// connect alias
            _oAlias.ImageScaling = ToolStripItemImageScaling.None;
            _oAlias.Click += new EventHandler(_oAlias_Click);
            _oAlias.ToolTipText = "Equate two items in different modules";
            oToolstrip.Items.Add(_oAlias);
            _Alias = _oAlias;
        }

        static FormConnect _oFormConnect = new FormConnect();

        void _oAlias_Click(object sender, EventArgs e)
        {
            CurrentModel.DeselectItems();
            Utility.Refresh();
            Reset();
            IsActive = true;
            CurrentState = State.Aliasing;
            UpdateButtons(sender);
        }

        void _oAnchor_Click(object sender, EventArgs e)
        {
            CurrentModel.DeselectItems();
            Utility.Refresh();
            Reset();
            IsActive = true;
            CurrentState = State.Anchoring;
            UpdateButtons(sender);
        }

        private void UpdateButtons(object sender)
        {
            if (sender is ToolStripButton)
            {
                ToolStripButton toolStripButton = (ToolStripButton)sender;
                UncheckAllButtons(toolStripButton);
                Utility.MouseImage = toolStripButton.Image;
            }
        }

        State CurrentState;

        private void Reset()
        {
            foreach (IDrawable ig in _ItemsToConnect)
                ig.IsSelected = false;

            _ItemsToConnect.Clear();
        }
        /// <summary>
        /// The reaction is made at mouse-up, so this is the main event
        /// </summary>
        /// <param name="e"></param>
        public override void OnMouseUp(HandledMouseEventArgs e)
        {
            if (!IsActive) return;
            try
            {
                switch (CurrentState)
                {
                    case State.Aliasing:
                        if (_ItemsToConnect.Count == 2)
                        {
                            int n = _ItemsToConnect.Count - 1;
                            HistoryManager.History.SetControllPoint("selected items made aliased of " + _ItemsToConnect[n]);
                            /*for (int i=0; i < _ItemsToConnect.Count - 1; ++i)
                              _ItemsToConnect[n].AddAlias(_ItemsToConnect[i]);
                            Reset();
                            _oInstance.UpdateButtons(_oInstance._Alias);*/

                            if (!(_ItemsToConnect[0].NullItem || _ItemsToConnect[1].NullItem))
                            {
                                Connector c = new ModuleConnector(_ItemsToConnect[0], _ItemsToConnect[1]);
                                if (c.IsVisible)
                                    CurrentModel.AddToModel(c);
                                else
                                    Utility.SetMessage("Error: Items must be in different modules");
                            }
                            Reset();
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                            Utility.Refresh();
                        }
                        break;

                    case State.Anchoring:
                        if (CurrentModel.Selected.Count + _ItemsToConnect.Count >= 2 && _ItemsToConnect.Count > 0)
                        {
                            int n = _ItemsToConnect.Count - 1;
                            HistoryManager.History.SetControllPoint("selected items anchored to " + _ItemsToConnect[n]);
                            if (_ItemsToConnect.Count == 2)
                            {
                                if (_ItemsToConnect[0].AnchoredSource == _ItemsToConnect[n])
                                    _ItemsToConnect[0].AnchoredSource = null;
                                else
                                    _ItemsToConnect[0].AnchoredSource = _ItemsToConnect[n];
                            }
                            else
                            {
                                for (int i = 0; i < _ItemsToConnect.Count - 1; ++i)
                                {
                                    _ItemsToConnect[i].AnchoredSource = _ItemsToConnect[n];
                                }
                                foreach (IDrawable id in CurrentModel.Selected)
                                {
                                    id.AnchoredSource = _ItemsToConnect[n];
                                }
                                CurrentModel.DeselectItems(false);
                            }
                            Reset();
                            _oInstance.UpdateButtons(_oInstance._Anchor);
                            Utility.Refresh();
                        }
                        break;

                    default:
                        break;
                }
            }
            catch (Exception) { Reset(); }
        }

        public override void OnMouseDown(HandledMouseEventArgs e)
        {
            if (!IsActive) return;

            PointF location = Utility.GetTransformedPoint(e.Location);
            List<IDrawable> oItems = CurrentModel.FindItems(location);

            if (oItems.Count < 1)    //if no items selected, deactivate
            {
                //IsActive = false;
                Reset();
                return;
            }

            if (oItems[oItems.Count - 1] != null)   //get the first item only
            {
                _ItemsToConnect.Add(oItems[oItems.Count - 1]); //add it to the list of items to connect
                oItems[oItems.Count - 1].IsSelected = true;
                e.Handled = true;
            }
        }

        public override void OnKeyDown(KeyEventArgs args)
        {
          
        }

        public override void OnKeyUp(KeyEventArgs args)
        {

        }

        /// <summary>
        /// called when tool is activated
        /// </summary>
        public override void OnActivate()
        {
            Reset();
        }

        /// <summary>
        /// Called when Tool is deactivated
        /// </summary>
        public override void OnDeactivate()
        {
            Reset();
            UncheckAllButtons();
        }


        public override void OnSelectionChanged()
        {

        }

        public override void SetupContextMenu(ToolStripMenuItem oStrip)
        {
            ToolCommand[] commands = GetDynamicCommandsArray();
            foreach (ToolCommand command in commands)
            {
                if (command != null)
                    oStrip.DropDownItems.Add(command.ToMenuItem());
            }
        }
        public override bool Handles(List<Type> oTypes)
        {
            bool bResult = true;
            foreach (Type t in oTypes)
            {
                bResult &= Handles(t);
                if (!bResult) return false;
            }
            return bResult;
        }

        private bool Handles(Type t)
        {
            return Utility.IsTypeNoAbstract(typeof(Athena.Objects.IDrawable), t);
        }

        class ToolCommand
        {
            private string _sCommand;

            public string Command
            {
                get { return _sCommand; }
                set { _sCommand = value; }
            }

            private Bitmap _Icon;
            public Bitmap Icon
            {
                get
                {
                    return _Icon;
                }
                set
                {
                    _Icon = value;
                }
            }

            private string _Description;
            public string Description
            {
                get
                {
                    return _Description;
                }
                set
                {
                    _Description = value;
                }
            }


            public ToolCommand()
            {
                _sCommand = null;
                _Icon = null;
            }

            /// <summary>
            /// Initializes a new instance of the ToolCommand class.
            /// </summary>
            /// <param name="sCommand"></param>
            /// <param name="icon"></param>
            /// <param name="description"></param>
            public ToolCommand(string sCommand, Bitmap icon, string description)
            {
                _sCommand = sCommand;
                _Icon = icon;
                _Description = description;
            }

            public ToolStripItem ToMenuItem()
            {
                if (_Icon == null && _sCommand == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {

                    ToolStripMenuItem oItem = new ToolStripMenuItem(_sCommand);
                    if (_Icon != null)
                        oItem.Image = _Icon;
                    oItem.Tag = _sCommand;
                    oItem.ToolTipText = _Description;
                    oItem.ImageScaling = ToolStripItemImageScaling.None;
                    oItem.Click += new EventHandler(CommandExecute);
                    return oItem;
                }
            }

            public ToolStripItem ToToolStripButton()
            {
                if (_Icon == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {
                    ToolStripButton oButton = new ToolStripButton(_sCommand);
                    if (_Icon != null)
                        oButton.Image = _Icon;
                    oButton.Checked = true;
                    oButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
                    oButton.Tag = _sCommand;
                    oButton.ImageScaling = ToolStripItemImageScaling.None;
                    oButton.ToolTipText = _Description;
                    oButton.Click += new EventHandler(CommandExecute);
                    return oButton;
                }
            }

            void CommandExecute(object sender, EventArgs e)
            {
                string sTag = "";
                if (sender is ToolStripButton)
                    sTag = (string)((ToolStripButton)sender).Tag;
                else if (sender is ToolStripMenuItem)
                    sTag = (string)((ToolStripMenuItem)sender).Tag;
                else
                    return;

                //since all are connectors, the following methods can be applied
                switch (sTag)
                {
                    case "Anchor to":
                        if (CurrentModel.Selected.Count > 0)
                        {
                            _oInstance.Reset();
                            _oInstance.IsActive = true;
                            _oInstance.CurrentState = State.Anchoring;
                            _oInstance.UpdateButtons(sender);
                            foreach (IDrawable id in CurrentModel.Selected)
                            {
                                _oInstance._ItemsToConnect.Add(id);
                            }
                        }
                        break;
                    case "Make Alias of":
                        if (CurrentModel.Selected.Count > 0)
                        {
                            _oInstance.Reset();
                            _oInstance.IsActive = true;
                            _oInstance.CurrentState = State.Aliasing;
                            _oInstance.UpdateButtons(sender);
                            foreach (IDrawable id in CurrentModel.Selected)
                            {
                                _oInstance._ItemsToConnect.Add(id);
                            }
                        }
                        break;
                    case "Remove Anchors":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            id.AnchoredSource = null;
                        }
                        break;
                    default:
                        break;
                }
            }


        }

        private ToolCommand[] GetDynamicCommandsArray()
        {
            return _oCommands;
        }

        static ToolCommand[] _oCommands = new ToolCommand[]
        {
            new ToolCommand("Anchor to", null , "Anchor this item to the next item you select"),
            new ToolCommand("Remove Anchors", null , "Remove all anchors that control this item"),
            new ToolCommand("Make Alias of", null , "Make this item an alias of the next item you select")
        };


    }
}
